//
//  config.swift
//  jocool
//
//  Created by tong on 16/6/11.
//  Copyright © 2016年 zhuxietong. All rights reserved.
//

import Foundation
import UIKit
import Eelay
import RxSwift

extension String{
    public func findMath(first reg:Regex)->String{
        return reg.firstMatch(in:self)?.captures.map({ str in
            return str ?? ""
        }).first ?? ""
    }
    public func find(reg:StaticString)->String{
        return Regex(reg).firstMatch(in:self)?.captures.map({ str in
            return str ?? ""
        }).first ?? ""
    }
}

public struct KValue{
    public let key:String
    public let value:String
    public var obj:NSMutableDictionary? = nil
}

public protocol KValueabel {
    var key:String{get}
    var value:String{get}
    var rawValue:KValue{get}
}

extension KValue: RawRepresentable{
    public init?(rawValue: String) {
        self.init(key: rawValue.findMath(first: Regex("^\\[(\\S+?)\\]")), value: rawValue.findMath(first: Regex("^\\[\\S+?\\](.+)$")))
    }
    public var rawValue: String {
        get { return "[\(key)]:\(value)"}
    }
    
}

extension KValue: ExpressibleByStringLiteral,Equatable {
    public init(stringLiteral value: StringLiteralType) {
        self.init(rawValue: "\(value)")!
    }
}

extension RawRepresentable where Self.RawValue == KValue
{
    public var key:String{
        return self.rawValue.key
    }
    public var value:String{
        return self.rawValue.value
    }
}





public struct UniqueValue{
    static let allModels = NSMutableDictionary()
    public let key:String
    func setData(obj:NSMutableDictionary,notice:Bool=true) {
        UniqueValue.allModels["\(key)"] = obj
        if notice{
            status.onNext(obj)
        }
    }
   
    public var obj:NSMutableDictionary{
        get{
            return UniqueValue.allModels.get(node: key, defaultV: NSMutableDictionary())
        }
    }
    public init(key: String) {
        if let a = UniqueValue.maps.filter({ u in
            return u.key == key
        }).first{
            self = a
        }else{
            self.key = key
            UniqueValue.maps.append(self)
        }
        
    }
    public var status:PublishSubject<NSMutableDictionary> = PublishSubject<NSMutableDictionary>()
    static var maps:[UniqueValue] = []
}



extension UniqueValue: RawRepresentable{
    public init?(rawValue: String) {
        self.init(key: rawValue)
    }
    public var rawValue: String {
        get { return key}
    }

    
}

extension UniqueValue: ExpressibleByStringLiteral,Equatable {
    public init(stringLiteral value: StringLiteralType) {
        self.init(rawValue: "\(value)")!
    }
    
}

extension RawRepresentable where Self.RawValue == UniqueValue
{
    public var key:String{
        return self.rawValue.key
    }
    public var status:PublishSubject<NSMutableDictionary>{
        return self.rawValue.status
    }
    public var obj:NSMutableDictionary{
        return self.rawValue.obj
    }
    public func update(obj:NSMutableDictionary?,notice:Bool=true){
        rawValue.setData(obj: obj ?? NSMutableDictionary(),notice: notice)
    }
  
    public var valid:Bool{
        return obj.allKeys.count > 0
    }
 
}



public struct ETag {
    public let name:String
    public let atrributes:[String:Any]
    public let text:String
    public let raw:String
    public init(element:String) {
        let info = ETag.parser(str: element)
        raw = element
        name = info.name
        atrributes = info.atrr
        text = info.text
    }
    
    public static func parser(str:String)->(name:String,text:String,atrr:[String:Any]){
        var atrs = [String:String]()
        let attrItems1 = Regex("(\\w+=\"[^\"]{0,}?\")").allMatches(in: str).map { r in
            return r.matchedString
        }
        for item in attrItems1 {
            let name = item.replacingAll(matching: "(\\w+?)=\"([^\"]{0,})\"", with: "$1")
            let value = item.replacingAll(matching: "(\\w+?)=\"([^\"]{0,})\"", with: "$2")
            atrs[name] = value
        }
        
        
        let attrItems2 = Regex("(\\w+='[^']{0,}?')").allMatches(in: str).map { r in
            return r.matchedString
        }
        for item in attrItems2 {
            let name = item.replacingAll(matching: "(\\w+?)='([^']{0,})'", with: "$1")
            let value = item.replacingAll(matching: "(\\w+?)='([^']{0,})'", with: "$2")
            atrs[name] = value
        }
        
        
        var tag = ""
        if let tagName = Regex("^<(\\w+?)").firstMatch(in: str)?.captures.first{
            if let tagName_ = tagName{
                tag = tagName_
            }
        }
        var text = ""
        if let textContent = Regex(">(.*?)<").firstMatch(in: str)?.captures.first{
            if let textContent_ = textContent{
                text = textContent_
            }
        }
        
        return (tag,text,atrs)
    }
    
}



extension ETag: RawRepresentable{
    public init?(rawValue: String) {
        self.init(element:rawValue)
    }
    public var rawValue: String {
        get { return raw}
    }
    
}

extension ETag: ExpressibleByStringLiteral,Equatable {
    public init(stringLiteral value: StringLiteralType) {
        self.init(rawValue: "\(value)")!
    }
}

extension RawRepresentable where Self.RawValue == ETag
{
    public var name:String{
        return self.rawValue.name
    }
    public var key:String{
        return self.rawValue.name
    }
    public var atrributes:[String:Any]{
        return self.rawValue.atrributes
    }
    public var text:String{
        return self.rawValue.text
    }
    public subscript(_ atrr:String)->String{
        if  atrributes.keys.contains(atrr){
            let v = atrributes[atrr] ?? ""
            return "\(v)"
        }
        return ""
    }
}
extension CaseKeyInit where Self.RawValue == ETag
{
    
    public init(key:String) {
        let items = Self.allCases
        guard let case_ = items.filter({ o in
            return o.key == key
        }).first else{
            self = items.first!
            return
        }
        self = case_
    }
}
public protocol CaseKeyInit:RawRepresentable,CaseIterable {
    
}
